package com.polaris.live.common.mvvm.viewmodel

import androidx.annotation.MainThread
import androidx.annotation.StringRes
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import com.blankj.utilcode.util.StringUtils
import com.polaris.live.common.mvvm.livedata.EventLiveData
import com.polaris.live.common.util.LogExt
import com.polaris.live.common.util.loading.OnCancelListener
import com.polaris.live.common.util.loading.OnDismissListener
import com.polaris.live.translation.R
import java.util.LinkedList
import java.util.concurrent.atomic.AtomicBoolean

/**
 * 基类viewModel
 *
 * @author Created by 半仙 on 2023/7/31/031 15:22
 */
open class BaseViewModel : ViewModel() {

    val loadingChange: UiLoadingChange by lazy {
        UiLoadingChange()
    }

    /**
     * 显示loading
     */
    fun showLoading(
        @StringRes message: Int,
        cancelable: Boolean = false,
        hasShadowBg: Boolean = false,
        cancelTime: Long = 15 * 1000L,
        waitTime: Long = 500L,
        useView: Boolean = true,
        onCancelListener: OnCancelListener? = null,
        onDismissListener: OnDismissListener? = null
    ) {
        showLoading(
            StringUtils.getString(message),
            cancelable,
            hasShadowBg,
            cancelTime,
            waitTime,
            useView,
            onCancelListener,
            onDismissListener
        )
    }

    /**
     * 显示loading
     */
    fun showLoading(
        message: String = StringUtils.getString(R.string.loading),
        cancelable: Boolean = false,
        hasShadowBg: Boolean = false,
        cancelTime: Long = 15 * 1000L,
        waitTime: Long = 500L,
        useView: Boolean = true,
        onCancelListener: OnCancelListener? = null,
        onDismissListener: OnDismissListener? = null
    ) {
        loadingChange.showDialog.value = ViewModelLoading(
            message,
            cancelable,
            hasShadowBg,
            cancelTime,
            waitTime,
            useView,
            onCancelListener,
            onDismissListener
        )
    }

    /**
     * 关闭loading
     */
    fun dismissDialog(waitTime: Long = 0L) {
        loadingChange.dismissDialog.value = waitTime
    }
}

/**
 * 内置封装好的可通知Activity/fragment 显示隐藏加载框
 */
class UiLoadingChange {

    //显示加载框
    val showDialog by lazy { EventLiveData<ViewModelLoading>() }

    //隐藏
    val dismissDialog by lazy { EventLiveData<Long>() }

}

/**
 * loading参数封装
 */
class ViewModelLoading(
    val message: String,
    val cancelable: Boolean,
    val hasShadowBg: Boolean,
    val cancelTime: Long,
    val waitTime: Long,
    val useView: Boolean,
    val onCancelListener: OnCancelListener?,
    val onDismissListener: OnDismissListener?
)

/**
 * 一次性响应的事件
 */
class SingleLiveEvent<T> : MutableLiveData<T>() {

    private val mPending = AtomicBoolean(false)

    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        if (hasActiveObservers()) {
            LogExt.logE(TAG, "Multiple observers registered but only one will be notified of changes.")
        }
        // Observe the internal MutableLiveData
        super.observe(owner) { t ->
            if (mPending.compareAndSet(true, false)) {
                observer.onChanged(t)
            }
        }
    }

    override fun postValue(value: T) {
        throw IllegalStateException("SingleLiveEvent does not support postValue, please use setValue.")
    }

    @MainThread
    override fun setValue(t: T?) {
        mPending.set(true)
        super.setValue(t)
    }

    companion object {

        private const val TAG = "SingleLiveEvent"
    }
}

/**
 * 顺序事件，每一个事件保证会被消费一次
 */
class SequentialLiveData<T> : MutableLiveData<T>() {

    private val mData = HashMap<LifecycleOwner, LinkedList<T>>()

    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        mData[owner] = LinkedList<T>()

        super.observe(owner) observe2@{
            val iterator = mData[owner]?.iterator()
                ?: return@observe2

            while (iterator.hasNext()) {
                observer.onChanged(iterator.next())

                iterator.remove()
            }
        }
    }

    override fun postValue(value: T) {
        throw IllegalStateException("SequentialLiveData does not support postValue, please use setValue.")
    }

    @MainThread
    override fun setValue(value: T) {
        mData.forEach { (_, u) ->
            u.offer(value)
        }
        super.setValue(value)
    }
}